from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from django.core.exceptions import ImproperlyConfigured
from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from django.views.generic import ListView, TemplateView, CreateView, UpdateView, DetailView

from tb3.utils import queryset_export_excel, list_export_excel, convert_choices_to_dict
from .signals import *
from .utils import calculate_product_batch_material_list, tank_state_list, export_material_list, export_batch_list, \
    product_batch_detail, calculate_product_batch_cost


def get_obj_permission_required(obj):
    if obj.permission_required is None:
        if obj.model is None:
            raise ImproperlyConfigured(
                '{0} is missing the model attribute.'.format(obj.__class__.__name__)
            )
        else:
            obj.permission_required = obj.get_required_object_permissions(obj.model)
    if isinstance(obj.permission_required, str):
        perms = (obj.permission_required,)
    else:
        perms = obj.permission_required
    return perms


class AppListView(PermissionRequiredMixin, ListView):
    paginate_by = 10
    object_list = None
    list_filter = None

    @staticmethod
    def get_required_object_permissions(model_cls):
        return '{0}.view_{1}'.format(getattr(model_cls, '_meta').app_label, getattr(model_cls, '_meta').model_name)

    def get_permission_required(self):
        return get_obj_permission_required(self)

    def get_queryset(self):
        queryset = super().get_queryset()
        if self.list_filter:
            filter_data = dict()
            for field in self.list_filter:
                field_value = self.request.GET.get(field)
                if field_value:
                    filter_data[field] = field_value
            if filter_data:
                queryset = queryset.filter(**filter_data)
        return queryset

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data(object_list=object_list, **kwargs)
        if isinstance(self.get_queryset(), QuerySet):
            context['data_length'] = self.get_queryset().count()
        elif isinstance(self.get_queryset(), list):
            context['data_length'] = len(self.get_queryset())
        page_range = getattr(context['paginator'], 'page_range')
        current_page_num = getattr(context['page_obj'], 'number')
        page_range_list = list()
        if page_range:
            if len(page_range) > 7:
                for p_num in page_range:
                    if -3 < p_num - current_page_num < 3:
                        page_range_list.append(p_num)
                if 1 not in page_range_list:
                    page_range_list.insert(0, 1)
                    if 2 not in page_range_list:
                        page_range_list.insert(1, 0)
                if page_range[-1] not in page_range_list:
                    if page_range[-2] not in page_range_list:
                        page_range_list.append(0)
                    page_range_list.append(page_range[-1])
            else:
                for p_num in page_range:
                    page_range_list.append(p_num)
        context['page_range'] = page_range_list
        if self.list_filter:
            if isinstance(self.list_filter, list):
                for field in self.list_filter:
                    context[field] = getattr(
                        getattr(getattr(self.model, field), 'field'), 'related_model'
                    ).objects.all()
        return context


class AppDetailView(PermissionRequiredMixin, DetailView):

    @staticmethod
    def get_required_object_permissions(model_cls):
        return '{0}.view_{1}'.format(getattr(model_cls, '_meta').app_label, getattr(model_cls, '_meta').model_name)

    def get_permission_required(self):
        return get_obj_permission_required(self)


class AppCreateView(PermissionRequiredMixin, CreateView):

    @staticmethod
    def get_required_object_permissions(model_cls):
        return '{0}.add_{1}'.format(getattr(model_cls, '_meta').app_label, getattr(model_cls, '_meta').model_name)

    def get_permission_required(self):
        return get_obj_permission_required(self)

    def get_success_url(self):
        if self.request.GET:
            if self.request.GET.get('next'):
                return self.request.GET.get('next')
        return super().get_success_url()


class AppUpdateView(PermissionRequiredMixin, UpdateView):

    @staticmethod
    def get_required_object_permissions(model_cls):
        return '{0}.change_{1}'.format(getattr(model_cls, '_meta').app_label, getattr(model_cls, '_meta').model_name)

    def get_permission_required(self):
        return get_obj_permission_required(self)


class PermissionRequireTemplateView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView):
    login_url = '/wiki/_accounts/login/'
    permission_required = None


class LoginRequiredTemplateView(LoginRequiredMixin, TemplateView):
    template_name = None


class ProductView(ListView):
    template_name = 'oa/products.html'
    model = PackageGroup
    paginate_by = None

    def get_queryset(self):
        queryset = super().get_queryset().filter(is_show=True).order_by('code')
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_count'] = self.get_queryset().count()
        context['title'] = _('产品信息')
        return context


class KegProblemView(TemplateView):
    template_name = 'oa/keg_problems.html'

    def get_queryset(self):
        if self.request.GET.get('code') == 'cbwi2cqevq1eivi3qevbe':
            queryset = FeedBack.objects.filter(feedback_category__id__exact=2)
        else:
            queryset = FeedBack.objects.none()
        date_start = self.request.GET.get('date_start')
        date_end = self.request.GET.get('date_end')
        if date_start:
            queryset = queryset.filter(feedback_date__gte=date_start)
        if date_end:
            queryset = queryset.filter(feedback_date__lte=date_end)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['objects'] = self.get_queryset()
        context['total_count'] = self.get_queryset().count()
        total_kegs = self.get_queryset().aggregate(Sum('amount'))
        context['total_kegs'] = total_kegs['amount__sum']
        return context


class ProductBatchCostView(PermissionRequireTemplateView):
    template_name = 'oa/product_batch_cost.html'
    permission_required = ('oa.view_moneyinout', )
    permission_denied_message = '权限不够，找老板'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        pk = kwargs.get('pk', 0)
        date_before = self.request.GET.get('date_before')
        if pk:
            data = calculate_product_batch_cost(pk, date_before=date_before)
            if data:
                context['data'] = data
        return context


class ProductBatchCostListView(PermissionRequireTemplateView):
    template_name = 'oa/product_batch_cost_list.html'
    permission_required = ('oa.view_moneyinout', )
    permission_denied_message = '权限不够，找老板'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        q = self.request.GET.get('q')
        date_before = self.request.GET.get('date_before')
        product_batches = ProductBatch.objects.filter(need_statistic=True)
        if q:
            product_batches = product_batches.filter(
                Q(code__icontains=q) | Q(product_name__name__icontains=q)
            ).distinct()
        if date_before:
            product_batches = product_batches.filter(start_date__lte=date_before)
        product_batches = product_batches.order_by('start_date')
        data = dict()
        data['product_batches'] = list()
        for pb in product_batches:
            data['product_batches'].append(calculate_product_batch_cost(pb.pk, date_before=date_before))
        if data:
            context['data'] = data
        return context

    def get(self, request, *args, **kwargs):
        if request.GET.get('update_act_volume') == 'true':
            pbs = ProductBatch.objects.filter(need_statistic=True)
            for pb in pbs:
                act_volume = pb.calculate_act_volume()
                if not round(float(pb.act_volume) - float(act_volume)) == 0:
                    pb.act_volume = act_volume
                    pb.save()
        context = self.get_context_data(**kwargs)
        if request.GET.get('excel') == "1":
            return export_batch_list(data=context['data'])
        return self.render_to_response(context)


class ProductBatchDetailView(PermissionRequiredMixin, TemplateView):
    template_name = 'oa/product_batch_detail.html'
    permission_required = []

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        pk = kwargs.get('pk', 0)
        key = self.request.GET.get('key', '')
        if pk:
            qr_key = ProductBatch.objects.get(pk=pk).qr_key
            if self.request.user.has_perm('oa.view_productbatch') or key == qr_key:
                data = product_batch_detail(pk)
                if data:
                    context['data'] = data
        return context


class ProductBatchMaterialListView(PermissionRequireTemplateView):
    template_name = 'oa/product_batch_material_list.html'
    permission_required = ('oa.view_moneyinout', )
    permission_denied_message = '权限不够，找老板'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        date_before = self.request.GET.get('date_before')
        data = calculate_product_batch_material_list(date_before, self.request.GET.get('q'))
        if data:
            context['data'] = data
        return context

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        if request.GET.get('excel') == "1":
            return export_material_list(date_before=request.GET.get('date_before'), q=request.GET.get('q'))
        return self.render_to_response(context)


class TankStateListView(PermissionRequireTemplateView):
    template_name = 'oa/tank_state_list.html'
    permission_required = ('oa.view_productbatch', )
    permission_denied_message = '权限不够，找老板'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        data = tank_state_list()
        if data:
            context['data'] = data
        return context

    def update_state(self):
        fields = ['equipment_id', 'tank_state']
        data = dict()
        for f in fields:
            data[f] = self.request.POST.get(f)
            if data[f]:
                if isinstance(data[f], list):
                    data[f] = data[f][0]
        if data['equipment_id'] and data['tank_state']:
            current_batch = EquipmentCurrentProductBatch.objects.filter(equipment_id=data['equipment_id'])
            if current_batch:
                current_batch.update(tank_state=data['tank_state'])
                if data['tank_state'] in convert_choices_to_dict(choices_product_state):
                    ProductBatch.objects.filter(
                        pk=current_batch.first().product_batch_id
                    ).update(product_state=data['tank_state'])

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        context['equipments'] = Equipment.objects.filter(is_tank=True)
        states = convert_choices_to_dict(choices_tank_state)
        states.pop('plan')
        context['states'] = states
        return self.render_to_response(context)

    def post(self, request, *args, **kwargs):
        self.update_state()
        return self.get(request, *args, **kwargs)


class MaterialInListView(AppListView):
    model = MaterialIn
    template_name = 'oa/material_in_list.html'
    permission_denied_message = '权限不够，找老板'
    paginate_by = 20

    def get_queryset(self):
        queryset = super().get_queryset().order_by('related_order__record_date')
        supplier_id = self.request.GET.get('supplier_id')
        date_start = self.request.GET.get('date_start')
        date_end = self.request.GET.get('date_end')
        if supplier_id:
            queryset = queryset.filter(related_purchase_detail__related_purchase_order__supplier_id=int(supplier_id))
        if date_start:
            queryset = queryset.filter(related_order__record_date__gte=date_start)
        if date_end:
            queryset = queryset.filter(related_order__record_date__lte=date_end)
        queryset = queryset.distinct()
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['suppliers'] = Supplier.objects.all()
        return context

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(object_list=self.get_queryset())
        columns = [
            'pk', 'related_order__related_purchase_order__order_date',
            'related_order__code', 'related_order__related_purchase_order__code',
            'material__material_category__name',
            'material__code', 'material__name',
            'related_order__related_purchase_order__supplier__name', 'unit',
            'material_batch__package_unit__display', 'related_purchase_detail__amount', 'amount',
            'related_purchase_detail__price', 'unit_price', 'unit_cost',
            'related_purchase_detail__exp_record_date', 'related_order__record_date',
        ]
        if request.GET.get('excel') == "1":
            queryset = self.get_queryset().values(*columns)
        else:
            queryset = context['object_list'].values(*columns)
        data_list = list()
        for row in queryset:
            row_data = dict()
            for k in columns:
                row_data[k] = row.get(k)
            if row_data['amount'] is not None and row_data['unit_price'] is not None:
                row_data['current_price'] = round(float(row_data['amount']) * float(row_data['unit_price']), 4)
            else:
                row_data['current_price'] = 0
            data_list.append(row_data)
        columns.insert(13, 'current_price')
        context['rows'] = data_list
        if request.GET.get('excel') == "1":
            headers = [
                'ID', '下单日期', '入库单号', '采购单号', '原料类别', '物料编码', '原料名称', '供应商',
                '单位', '包装规格', '购进数量', '到货数量',
                '总价/元', '到货金额/元', '单价/元', '单位成本/元', '预计到货时间', '实际到货时间']
            filename = 'media/{0}_{1}.xls'.format(
                'material_in', datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
            return list_export_excel(data_list, headers, columns, filename)
        return self.render_to_response(context)


class MaterialPurchaseListView(AppListView):
    model = MaterialPurchaseOrderItem
    template_name = 'oa/material_purchase_list.html'
    permission_denied_message = '权限不够，找老板'
    paginate_by = 20

    def get_queryset(self):
        queryset = super().get_queryset().order_by('related_purchase_order__order_date')
        supplier_id = self.request.GET.get('supplier_id')
        date_start = self.request.GET.get('date_start')
        date_end = self.request.GET.get('date_end')
        if supplier_id:
            queryset = queryset.filter(related_purchase_order__supplier_id=int(supplier_id))
        if date_start:
            queryset = queryset.filter(Q(related_purchase_order__order_date__gte=date_start) | Q(
                related_material_in__related_order__record_date__gte=date_start))
        if date_end:
            queryset = queryset.filter(related_purchase_order__order_date__lte=date_end)
        queryset = queryset.distinct()
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['suppliers'] = Supplier.objects.all()
        return context

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(object_list=self.get_queryset())
        if request.GET.get('excel') == "1":
            queryset = self.get_queryset()
            headers = [
                'ID', '下单日期', '采购订单', '原料类别', '物料编码', '原料名称', '供应商',
                '单位', '包装规格', '购进数量', '到货数量',
                '总价/元', '单价/元', '单位成本/元', '预计到货时间', '实际到货时间']
            columns = [
                'pk', 'related_purchase_order__order_date', 'related_purchase_order__code',
                'material__material_category__name',
                'material__code', 'material__name',
                'related_purchase_order__supplier__name', 'package_unit__unit',
                'package_unit__display',
                'amount', 'amount_in', 'price', 'unit_price', 'unit_cost',
                'exp_record_date', 'related_material_in__related_order__record_date',
            ]
            filename = 'media/{0}_{1}.xls'.format(
                'material_in', datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
            return queryset_export_excel(queryset, headers, columns, filename)
        return self.render_to_response(context)


class MaterialBatchStorageListView(AppListView):
    # 原料库存统计页面
    model = MaterialBatch
    template_name = 'oa/material_batch_list.html'
    permission_denied_message = '权限不够，找老板'
    paginate_by = 20
    values = [
        'pk',
        'material__material_category__name',
        'material__code',
        'material__name',
        'code',
        'package_unit__unit',
        'package_unit__display',
        'left_amount',
        'unit_price',
        'unit_cost'
    ]
    values_storage = [
        'pk',
        'material_batch__pk',
        'left_amount',
    ]
    total_assets = 0

    def get_queryset(self):
        queryset = super().get_queryset().order_by('material__code', 'expiration_date')  # 根据原料编号和过期日期排序
        # 数据筛选
        material_category_id = self.request.GET.get('material_category_id')
        q = self.request.GET.get('q')
        category_type = self.request.GET.get('category_type')
        if material_category_id:
            queryset = queryset.filter(material__material_category_id=int(material_category_id))
        if q:
            queryset = queryset.filter(
                Q(material__name__icontains=q) | Q(material__code__icontains=q)
            ).distinct()
        if category_type:
            queryset = queryset.filter(
                material__material_category__category_type=int(category_type)
            )
        # 数据抽取
        queryset = queryset.values(*self.values)
        # 如果有时间区间
        date_start = self.request.GET.get('date_start')  # 起始时间
        date_end = self.request.GET.get('date_end')  # 截止时间
        date_start_data = dict()
        date_end_data = dict()
        if date_start and date_end:
            # 如果有时间区间，在库存变动记录里面获取库存
            mbs = MaterialBatchStorage.objects.order_by('-record_datetime')
            # 有筛选条件
            if category_type:
                mbs = mbs.filter(
                    material_batch__material__material_category__category_type=int(category_type)
                )
            if q:
                mbs = mbs.filter(
                    Q(material_batch__material__name__icontains=q) | Q(material_batch__material__code__icontains=q)
                ).distinct()
            # 进行数据筛选
            mbs_start = mbs.filter(
                record_datetime__lt='{} 0:0:0.0'.format(date_start)
            ).values(*self.values_storage)
            mbs_end = mbs.filter(
                record_datetime__lte='{} 23:59:59.999999'.format(date_end)
            ).values(*self.values_storage)
            # 只获取最后一次记录
            for mb in mbs_start:
                if mb['material_batch__pk'] not in date_start_data:
                    date_start_data[mb['material_batch__pk']] = mb
            for mb in mbs_end:
                if mb['material_batch__pk'] not in date_end_data:
                    date_end_data[mb['material_batch__pk']] = mb
        total_assets = 0
        for qs in queryset:
            assets = 0
            if date_start and date_end:
                qs['mbs_start'] = 0
                qs['mbs_end'] = 0
                if qs['pk'] in date_start_data:
                    qs['mbs_start'] = date_start_data[qs['pk']]['left_amount']
                if qs['pk'] in date_end_data:
                    qs['mbs_end'] = date_end_data[qs['pk']]['left_amount']
                if qs['mbs_end']:
                    if qs['unit_cost']:
                        assets = float(qs['unit_cost']) * float(qs['mbs_end'])
            else:
                if qs['unit_cost']:
                    assets = float(qs['unit_cost']) * float(qs['left_amount'])
            qs['assets'] = assets
            total_assets += assets
        self.total_assets = total_assets
        queryset, raw_queryset = list(), queryset
        for qs in raw_queryset:
            if date_start and date_end:
                if qs['mbs_start'] or qs['mbs_end']:
                    queryset.append(qs)
            else:
                if qs['left_amount']:
                    queryset.append(qs)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['material_categories'] = MaterialCategory.objects.all()
        context['category_types'] = convert_choices_to_dict(category_type_choices)
        context['total_assets'] = self.total_assets
        return context

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(object_list=self.get_queryset())
        if request.GET.get('excel') == "1":
            queryset = self.get_queryset()
            headers = [
                'ID', '原料类别', '物料编码', '原料名称', '批次号', '包装规格', '单位', '当前数量', '期初数量',
                '期末数量', '采购单价/元', '单位成本/元', '结存金额/元']
            columns = [
                'pk',
                'material__material_category__name',
                'material__code',
                'material__name',
                'code',
                'package_unit__display',
                'package_unit__unit',
                'left_amount',
                'mbs_start',
                'mbs_end',
                'unit_price',
                'unit_cost',
                'assets'
            ]
            filename = 'media/{0}_{1}.xls'.format(
                'material_batch', datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
            return list_export_excel(queryset, headers, columns, filename)
        return self.render_to_response(context)


class ProductPriceListView(PermissionRequireTemplateView):
    template_name = 'oa/product_price_list.html'
    permission_required = ('oa.view_productsalesprice', )
    permission_denied_message = '权限不够，找老板'

    def get_queryset(self):
        queryset = ProductSalesPrice.objects.filter(
            is_active=True
        ).filter(
            price__gt=0
        ).order_by(
            'package_group__code', 'price'
        )
        if not self.request.user.is_superuser:
            queryset = queryset.filter(is_public=True)
        sales_channel_type = self.request.GET.get('sales_channel_type', 1)
        if sales_channel_type:
            queryset = queryset.filter(sales_channel__sales_channel_type=int(sales_channel_type))
        sales_channel_id = self.request.GET.get('sales_channel_id')
        if sales_channel_id:
            queryset = queryset.filter(sales_channel_id=sales_channel_id)
        q = self.request.GET.get('q')
        if q:
            queryset = queryset.filter(
                Q(package_group__code__icontains=q) | Q(package_group__name__icontains=q)
            ).distinct()
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['objects'] = self.get_queryset()
        context['sales_channel_type'] = convert_choices_to_dict(choices_sales_channel_type)
        sales_channel_type = self.request.GET.get('sales_channel_type', 1)
        sales_channels = SalesChannel.objects.filter(sales_channel_type=int(sales_channel_type))
        if sales_channels.count() > 1:
            context['sales_channels'] = sales_channels
        return context
